<h2>Why is this an issue?</h2>
<p>Numbers in JavaScript are stored in <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">double-precision 64-bit binary
format IEEE 754</a>. Like any other number encoding occupying a finite number of bits, it is unable to represent all numbers.</p>
<p>The values are stored using 64 bits in the following form:</p>
<ul>
  <li> 1 bit for the sign (positive or negative) </li>
  <li> 11 bits for the exponent (2<sup>n</sup>). -1022 ≤ n ≤ 1023 </li>
  <li> 52 bits for the significand (or mantissa) </li>
</ul>
<p>The actual value of the stored number will be <code>(-1)<sup>sign</sup> * (1 + significand) * 2 <sup>exponent</sup></code></p>
<p>Given this structure, there are limits in both <strong>magnitude</strong> and <strong>precision</strong>.</p>
<p>Due to the 52 bits used for the significand, any arithmetic in need of more precision than 2<sup>-52</sup> (provided by
<code>Number.EPSILON</code>) is subject to rounding.</p>
<p>In terms of magnitude, the largest number the 64 bits of the format can store is 2<sup>1024</sup> - 1 (<code>Number.MAX_VALUE</code>).</p>
<p>However, because the 52 bits of the significand, only integers between -(2<sup>53</sup> - 1) (<code>Number.MIN_SAFE_INTEGER</code>) and
2<sup>53</sup> - 1 (<code>Number.MAX_SAFE_INTEGER</code>) can be represented exactly and be properly compared.</p>
<pre>
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2;  // true
</pre>
<p>JavaScript provides the <code>bigint</code> primitive to represent values which are too large to be represented by the number primitive. BigInts
are created by appending <code>n</code> to the end of an integer literal, or by calling the <code>BigInt()</code> function (without the new operator),
with an integer or a string.</p>
<pre>
const myBigInt = BigInt(Number.MAX_SAFE_INTEGER);
myBigInt + 1n === myBigInt + 2n;  // false
</pre>
<h2>How to fix it</h2>
<p>For large numbers, JavaScript provides the helper function <code>Number.isSafeInteger()</code> to test if a number is between the safe limits.</p>
<p>When you need to store a large number, use <code>BigInt</code>. <code>bigint</code> and <code>number</code> primitives can be compared between them
as usual (e.g. <code>&gt;</code>, <code>==</code>), but pay attention that arithmetic operations (<code>+</code> <code>*</code> <code>-</code>
<code>%</code> <code>**</code>) between both types raise an error unless they are converted to the same type. Use the <code>BigInt</code> and
<code>Number</code> functions to convert between both types:</p>
<pre>
const myNumber = Number(myBigInt);
const myBigInt = BigInt(myNumber);
</pre>
<p>Be careful converting values back and forth, however, as the precision of a <code>bigint</code> value may be lost when it is coerced to a
<code>number</code> value.</p>
<h3>Code examples</h3>
<h4>Noncompliant code example</h4>
<pre>
const foo = 2312123211345545367  // Noncompliant: will be stored as 2312123211345545000
const bar = BigInt(2312123211345545367);  // Noncompliant: parameter is first parsed as an integer and thus rounded
</pre>
<h4>Compliant solution</h4>
<pre>
const foo = BigInt('2312123211345545367');
const bar = 2312123211345545367n;
</pre>
<p>When in need of more decimal precision, it is recommended to use a dedicated library to ensure that calculation errors are not introduced by
rounding.</p>
<h4>Noncompliant code example</h4>
<pre>
const baz = 0.123456789123456789 // Noncompliant: will be stored as 0.12345678912345678
</pre>
<h4>Compliant solution</h4>
<pre>
// use a library like decimal.js for storing numbers containing many decimal digits
import { Decimal } from 'decimal.js';
const bar = new Decimal('0.123456789123456789');
</pre>
<h2>Resources</h2>
<h3>Documentation</h3>
<ul>
  <li> <a href="https://eslint.org">eslint</a> - Rule <a href="https://eslint.org/docs/latest/rules/no-loss-of-precision">no-loss-of-precision</a>
  </li>
  <li> MDN web docs - <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding">Number
  encoding</a> </li>
  <li> MDN web docs - <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt">BigInt</a> </li>
  <li> Wikipedia - <a href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">Double-precision floating-point format</a> </li>
  <li> Wikipedia - <a href="https://en.wikipedia.org/wiki/IEEE_754">IEEE 754 Standard</a> </li>
</ul>
